#! /usr/bin/perl -w

# 实现在本地音乐仓库中按给写条件搜索
# 并可以选择播放
# 这个脚本依靠 mplayer 播放音频
# 发现也有播放mp3的CPAN模块
# 但需要另外安装xaudio sdk
# 而且好像还没有支持wma的
# 脚本用法: 参看 usage()
# 
# Author: Jiahuan Li <huanlf@gmail.com>
# License: GPL v2

use strict;
use File::Find;
use File::Basename;
use Getopt::Std;
use Term::ANSIColor qw(:constants);
$Term::ANSIColor::AUTORESET = 1;
$| = 1;

$SIG{INT} = $SIG{TERM} = sub { exit 0 };
#支持的扩展名
my $support_type = qr/\.(mp3|wma|mpg|wav|ogg|rmvb|rm|avi|wmv)$/i;

# 选项
my %opt = ();

#配置文件，保存音乐仓库
my $conf = "$ENV{HOME}/.myplayer.conf";

# 本地mp3仓库
my @mp3_dir = ();

getopts("qhd:a:", \%opt);
if ($opt{'h'}){
	&usage();
}

#从选项获得音乐仓库
if ($opt{'d'}){
	my @d = ($opt{'d'});
	while ($ARGV[0] && -d $ARGV[0]){
		push(@d, $ARGV[0]);
		shift;
	}
	&check_dir(@d);
	die "No music repositaries found.\n" unless @mp3_dir;
}

if ($opt{'a'}){
	 foreach ( split (/,/, $opt{'a'}) ){
		&check_dir($_);
	}
}
	
#从配置文件获得音乐仓库
if ( ! -f $conf ){
	open (CONF, "> $conf") || die "Can not create $conf: $!";
	print CONF "# This is configure file for myplayer.pl.
# Add your music directores here.
# Blank lines and lines begin with '#' will be ignored.
# Feedback and bug reports are welcome.
# Jiahuan Li <huanlf\@gmail.com>\n\n";
	&usage() unless ( $opt{'d'} || $opt{'a'} );
}

if ( ! $opt{'d'}){
	open (CONF, "< $conf") || die "Can not open configure file: $conf.\n$!";
	while(<CONF>){
		chomp;
		next if $_ eq '';
		next if /(\s+)?#/;
		next if /^\s+$/;
		s/^\s+//;
		s/\s+$//;
		&check_dir($_);
	}
}
&usage()  unless @mp3_dir;

# 查找 mplayer 播放器
die "Cant not find mplayer in \$PATH, have mplayer installed first,\
or make sure it's in your system \$PATH.\n" unless `which mplayer`;	

# 搜索对象，默认为all
my @mp3_to_find = @ARGV;
@mp3_to_find = ("all") unless @mp3_to_find;
my $mp3_to_find = "";

# mp3索引
my $mp3_index	= 1;

# 搜索结果
my %mp3_list	= ();

# 播放列表
my @mp3_to_play	= "";
my $mp3_to_play = "";

# 搜索进度计算器
my $search_process = 1;

print "Searching ... ... ... ";
find (\&find_mp3, @mp3_dir);
print "Done\n\n";
if ( ! %mp3_list ){
	print BOLD RED "Sorry, I find nothing.\n";
	exit;
}

# 数字化排序
if ( ! $opt{q}){
	foreach (sort {$a <=> $b} keys %mp3_list){
		print $_."\t".$mp3_list{$_}."\n";
	}
}

print <<"EOF";

Support format :[ 1..100 | all | Enter ]
EOF

# 播放列表，默认是all
print "Enter: ";
chomp ($mp3_to_play = <STDIN>) unless $opt{'q'} ;
$mp3_to_play = "all" if ( $mp3_to_play eq '');

@mp3_to_play = split (/\s/,$mp3_to_play);
foreach (@mp3_to_play){
	# 单曲播放
	if ( defined($mp3_list{$_}) ){
		print BOLD BLUE "No.$_\t";
		print BOLD BLUE "$mp3_list{$_}\n";		
		#在任务栏显示曲名
		print "\033]0;". basename($mp3_list{$_}) . "\007";
		system ("mplayer -nojoystick -nolirc -nortc $mp3_list{$_} 2>/dev/null");
        sleep 1;
	}
	# 随机播放全部
	elsif( /all/i){
		my @tmp_arr	= sort keys %mp3_list;
		&rand_play(1, $#tmp_arr+1);
	}
	#支持 1..20 范围列表, 改写代码后支持 20..1
	elsif( $_ =~ /(\d+)\.\.(\d+)/ ){
		my ($min, $max) = ($1, $2);
		($min, $max) = sort {$a<=>$b} ($min, $max);
		if ($mp3_list{$max} && $min > 0){
			&rand_play($min, $max)	
		}
		else{
			print BOLD RED "No.$_ invalid ..";
			last;
		}
	}
	else{
		print BOLD RED "Invalid index...\n";
	}
}

# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #

# 从仓库搜索音乐子过程
sub find_mp3 {

	# 忽略隐藏文件
	return if $File::Find::name =~ m|.*/\.+|;
	# 显示当前搜索进度
	my $back_space = length($search_process);
	print "$search_process" . "\b" x $back_space ;
	$search_process++;

	foreach $mp3_to_find (@mp3_to_find){
		# 只添加音频文件到列表
		last unless $File::Find::name =~ /$support_type/;
		#全部
		if ( $mp3_to_find =~ /\ball\b/i ){
			next if -d $File::Find::name; 
			$mp3_list{$mp3_index++} = $File::Find::name;
			next;
		}
		# 搜索结果
		if ( $_ =~ /$mp3_to_find/i ){
			$mp3_list{$mp3_index++} = $File::Find::name;
		}
	}
}

# 随机播放子过程
sub rand_play {
	my ($first, $last) = ($_[0], $_[1]);
	# $index 是列表的索引，最大值表示播放列表总数
	my $index=1;

	my $base = $first -1;

	# %list 中保存播放列表
	my %list = ();
	while($last >= $first){
		$list{$index++} = $mp3_list{$first++};
	}
	#让随机种子足够大
	my $seed_total = 2*$index;
	OUT:
	for($index--;$index >=1 ; $index--){
		# 改变随机数种子范围，让列表里的每一个值更有可能被取到
		for(my $seed=$seed_total; $seed> 0; $seed--){
			my $rand_index = int( rand($seed) );
			if ($list{$rand_index}){
				# 删除播放过的列表
				my $to_play = delete $list{$rand_index};
				print BOLD BLUE "\n\nNO." . ($base + $rand_index) . " $to_play\n";
				print "\033]0;" . basename($to_play) . "\007";
				system("mplayer -nojoystick -nolirc -nortc $to_play 2>/dev/null");
                sleep 1;
				next OUT;
			}
		}
	}
	# 漏网之鱼
	if(%list){
		foreach (keys %list){
			print BOLD BLUE "NO.". ($_+$base) ." $list{$_}\n";
			print "\033]0;" . basename($list{$_}) . "\007";
			system("mplayer -nojoystick -nolirc -nortc $list{$_} 2>/dev/null");
            sleep 1;
		}
	}
}

sub usage {
	print "Usage: $0 [-q] [-d music_directories] [-a music_directories] [music_to_find]\n";
	print "-d to indicate the music directories, dirs seperated by space.\n";
	print "-a to add music directories while read $conf as well\n";
	print "-q to auto play all the music found in music_directories\n";
	print "You can always add your music directories to $conf, one directory each line.\n\n";
	print "Feedback and bug reports are welcome.\n";
	print "Jiahuan Li <huanlf\@sohu.com>\n\n";
	exit 127;
}

# 将文件夹压入 @mp3_dir仓库
sub check_dir {
	foreach (@_){
		s/^~/$ENV{HOME}/g;
		if (-d){
			if (-r && -x){
				print "Adding $_ to repository.\n";
				push @mp3_dir, $_;
			}
		}
		else{
			warn "Invalid dir: $_\n";
		}

	}
}

END { 
    ## tty has no a title bar :)
    open( FH, "ps |" ) or die $!;
    while (<FH>) {
        if ( (split)[ -1 ] =~ /\bps$/ and (split)[ 1 ] =~ /\bpts/ ) {
            print "\033]0;" . "fei zhu" . "\007" and exit 0;
        }
    }
}

